package spring.cloud.tasks.executor.name_space.executor.task.task_item;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.ApplicationContextUtils;
import spring.cloud.tasks.common.Threads;
import spring.cloud.tasks.executor.api.InterruptedException;
import spring.cloud.tasks.executor.api.Task;
import spring.cloud.tasks.executor.api.TaskInfoManager;
import spring.cloud.tasks.executor.name_space.executor.task.TaskExecutor;
import spring.cloud.tasks.executor.name_space.executor.tasks_runtime_info.task_item_assign.TaskIdToTaskInstanceIdToTaskItemIndexListMapMap;
import spring.cloud.tasks.executor.name_space.executor.tasks_runtime_info.task_item_execute.TaskItemExecuteRuntimeContext;

import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Setter
@Getter
public class TaskItemExecute {
    protected final String taskId;
    protected final String linkId;
    protected final Integer taskItemIndex;
    protected final String taskItemParameter;
    protected final Integer secondAfterTaskStopCommandInstructed;
    public volatile boolean needStop = false;//外部指令
    protected TaskExecutor taskExecutor;
    //
    protected AtomicInteger status = new AtomicInteger(Status.RUNNING);
    protected boolean executed = false;//业务流程是否已经执行
    protected java.lang.Thread taskItemExecuteTaskThread;
    protected long startTime;
    protected long endTime;
    protected volatile TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext;
    private String threadName;

    //
    public TaskItemExecute(TaskExecutor taskExecutor, String taskId, String linkId, Integer taskItemIndex, String taskItemParameter, Integer secondAfterTaskStopCommandInstructed) {
        this.taskExecutor = taskExecutor;
        this.taskId = taskId;
        this.linkId = linkId;
        this.taskItemIndex = taskItemIndex;
        this.taskItemParameter = taskItemParameter;
        this.secondAfterTaskStopCommandInstructed = secondAfterTaskStopCommandInstructed;
    }

    public void bind(TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext) {
        this.taskItemExecuteRuntimeContext = taskItemExecuteRuntimeContext;
    }

    public boolean setTimeoutWhenStatusInit() {
        return status.compareAndSet(Status.RUNNING, Status.TIMEOUT);
    }

    public boolean setForceStopWhenStatusInit() {
        return status.compareAndSet(Status.RUNNING, Status.KILLED);
    }

    public void executeAndGetTaskItemExecuteResult() {
        /**
         *taskItemExecute运行在taskItemExecuteTask所在的Thread
         */
        taskItemExecuteTaskThread = java.lang.Thread.currentThread();
        try {
            beforeExecute();
            sleep(secondAfterTaskStopCommandInstructed);
            execute();
            //这以后就不能进行强制杀的必要了
            taskItemExecuteTaskThread = null;
            // 在此之后，不能再强制停止本线程
            executed = true;
        } catch (Throwable t) {
            //这以后就不能进行强制杀的必要了
            taskItemExecuteTaskThread = null;
            // 在此之后，不能再强制停止本线程
            executed = true;
            // 不是超时，不是强制停止。
            //this.taskItemExecuteResult = new TaskItemExecuteControlContext(TaskItemExecuteStatus.ERROR, t.getMessage());
            this.taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            this.taskItemExecuteRuntimeContext.setMessage(t.getMessage());
        } finally {
            afterExecute();
        }
    }

    public void sleep(Integer secondAfterTaskStopCommandInstructed) {
        if (secondAfterTaskStopCommandInstructed != null && secondAfterTaskStopCommandInstructed > 0) {
            for (int i = 1; i <= secondAfterTaskStopCommandInstructed; i++) {
                Threads.sleep();
            }
        }
    }

    public void beforeExecute() {
        this.startTime = System.currentTimeMillis();
    }

    public void afterExecute() {
        this.endTime = System.currentTimeMillis();
    }

    public long getExecutionTime() {
        return endTime - startTime;
    }

    public void execute() {
        try {
            /**
             * BizTask必须获取的是原型实例,其他情况需要自己改造
             */
            Task bean = (Task) ApplicationContextUtils.getApplicationContext().getBean(TaskInfoManager.getBeanId(linkId));
            bean.init(this, taskId, taskItemIndex, taskItemParameter);
            bean.execute();
            status.set(Status.SUCCESS);
            taskItemExecuteRuntimeContext.setStatus(Status.SUCCESS);

        } catch (InterruptedException e) {
            String message = e.getMessage();
            taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            taskItemExecuteRuntimeContext.setMessage(message);
        } catch (Throwable e) {
            String message = e.getMessage();
            taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            taskItemExecuteRuntimeContext.setMessage(message);
        }
    }

    public TaskIdToTaskInstanceIdToTaskItemIndexListMapMap getTaskIdToTaskInstanceIdToTaskItemIndexListMapMap() {
        return this.taskExecutor.getTaskIdToTaskInstanceIdToTaskItemIndexListMapMap();
    }
}
